package com.ruoyi.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.OperationLog;
import com.ruoyi.system.dto.design.OperationLogUpdateDTO;
import com.ruoyi.system.enums.BusinessTypeEnum;
import com.ruoyi.system.enums.OperateActionEnum;
import com.ruoyi.system.mapper.OperationLogMapper;
import com.ruoyi.system.service.IOperationLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 操作日志 Service 实现类
 */
@Service
public class OperationLogServiceImpl extends ServiceImpl<OperationLogMapper, OperationLog> implements IOperationLogService {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 新增操作日志（复用 MyBatis-Plus 的 save 方法，可添加自定义校验）
     */
    @Override
    public boolean addLog(OperationLog operationLog) {
        // 自定义校验：如业务类型、操作动作不能为空
        if (operationLog.getBusinessType() == null || operationLog.getOperateAction() == null) {
            throw new IllegalArgumentException("业务类型和操作动作不能为空");
        }
        // 若未设置操作人姓名，可从用户表查询补充（示例：需注入用户Service）
        // if (operationLog.getOperateUserName() == null && operationLog.getOperateUserId() != null) {
        //     User user = userService.getById(operationLog.getOperateUserId());
        //     if (user != null) {
        //         operationLog.setOperateUserName(user.getUserName());
        //     }
        // }
        return save(operationLog);
    }

    /**
     * 根据 ID 查询操作日志（复用 MyBatis-Plus 的 getById 方法，自动过滤已逻辑删除的记录）
     */
    @Override
    public OperationLog getLogById(Long id) {
        return getById(id);
    }

    /**
     * 分页查询操作日志（结合自定义筛选条件）
     */
    @Override
    public IPage<OperationLog> getLogPage(
            Integer pageNum,
            Integer pageSize,
            String businessType,
            Long operateUserId,
            LocalDateTime startTime,
            LocalDateTime endTime
    ) {
        // 1. 构建分页对象
        Page<OperationLog> page = new Page<>(pageNum, pageSize);

        // 2. 构建查询条件（LambdaQueryWrapper 避免硬编码字段名）
        LambdaQueryWrapper<OperationLog> queryWrapper = new LambdaQueryWrapper<>();
        // 业务类型筛选（非空才添加条件）
        if (businessType != null && !businessType.isEmpty()) {
            queryWrapper.eq(OperationLog::getBusinessType, businessType);
        }
        // 操作人ID筛选
        if (operateUserId != null) {
            queryWrapper.eq(OperationLog::getOperateUserId, operateUserId);
        }
        // 时间范围筛选（开始时间 ≤ operateTime ≤ 结束时间）
        if (startTime != null) {
            queryWrapper.ge(OperationLog::getOperateTime, startTime);
        }
        if (endTime != null) {
            queryWrapper.le(OperationLog::getOperateTime, endTime);
        }
        // 按操作时间倒序（最新的日志排在前面）
        queryWrapper.orderByDesc(OperationLog::getOperateTime);

        // 3. 执行分页查询（MyBatis-Plus 自动处理分页和逻辑删除）
        return page(page, queryWrapper);

        // 若使用自定义 SQL 分页（对应 Mapper 的 selectLogPage 方法），则替换为：
        // return baseMapper.selectLogPage(page, businessType, operateUserId, startTime, endTime);
    }

    @Override
    public List<OperationLog> getLogsByBusinessId(String businessId) {
        // 直接调用 Mapper 中定义的默认方法
        QueryWrapper<OperationLog> operationLogQueryWrapper = new QueryWrapper<>();
        operationLogQueryWrapper.eq("business_id", businessId)
                .in("operate_action", OperateActionEnum.getAllDesignActionCodes())
                .orderByDesc("operate_time");
        return baseMapper.selectList(operationLogQueryWrapper);
    }

    @Override
    public List<OperationLog> getLogsByBusinessIdForH5(String businessId) {
        return baseMapper.selectByBusinessIdForH5(businessId);
    }


    @Override
    public List<OperationLog> getLogsByBusinessIdAndType(String businessId, String businessType) {
        // 按业务ID+业务类型精确查询
        return baseMapper.selectByBusinessIdAndType(businessId, businessType);
    }

    /**
     * 逻辑删除操作日志（复用 MyBatis-Plus 的 removeById 方法，自动更新 is_deleted 字段）
     */
    @Override
    public boolean deleteLogById(Long id) {
        return removeById(id);
    }


    /**
     * 保存操作日志（自动填充操作用户信息）
     */
    @Override
    public boolean saveOperationLog(OperationLog log) {
        try {
            // 获取当前登录用户信息
            LoginUser loginUser = SecurityUtils.getLoginUser();
            if (loginUser != null) {
                log.setOperateUserId(loginUser.getUserId());
                log.setOperateUserName(loginUser.getUsername());
            } else {
                // 系统操作
                log.setOperateUserId(0L);
                log.setOperateUserName("系统");
                log.setOperateSource(OperationLog.Source.SYSTEM);
            }

            // 默认操作来源为PC网页端
            if (log.getOperateSource() == null) {
                log.setOperateSource(OperationLog.Source.PC_WEB);
            }

            // 设计相关日志默认不同步H5
            if (BusinessTypeEnum.DESIGN.getCode().equals(log.getBusinessType())
                    && log.getIsSyncH5Design() == null) {
                log.setIsSyncH5Design(0);
            }

            return save(log);
        } catch (Exception e) {
            // 日志保存失败不影响主业务
            logger.error("保存操作日志失败: {}", e.getMessage(), e);
            return false;
        }
    }


    /**
     * 修改操作日志（核心逻辑：限制修改字段+权限校验）
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult updateOperationLog(OperationLogUpdateDTO updateDTO) {
        // 1. 校验日志是否存在
        Long logId = updateDTO.getId();
        OperationLog log = getById(logId);
        if (log == null || log.getIsDeleted() == 1) {
            throw new ServiceException("操作日志不存在或已被删除");
        }

        // 2. 权限校验（示例：仅管理员或操作人本人可修改）
        Long currentUserId = SecurityUtils.getUserId(); // 从上下文获取当前用户ID
        if (!currentUserId.equals(log.getOperateUserId()) && !SecurityUtils.isAdmin(currentUserId)) {
            throw new ServiceException("无权限修改此日志（仅管理员或操作人本人可修改）");
        }

        // 3. 校验业务规则（示例：仅DESIGN类型可修改isSyncH5Design）
        List<String> businessTypes = Lists.newArrayList(BusinessTypeEnum.DESIGN.getCode(), BusinessTypeEnum.DESIGN_DATA_CHANGE.getCode());
        if (updateDTO.getIsSyncH5Design() != null && !businessTypes.contains(log.getBusinessType())) {
            throw new ServiceException("仅业务类型为【图纸设计】的日志可同步H5状态");
        }

       /* // 4. 校验操作来源合法性
        if (updateDTO.getOperateSource() != null) {
            OperateSourceEnum sourceEnum = OperateSourceEnum.getByCode(updateDTO.getOperateSource());
            if (sourceEnum == null) {
                throw new BusinessException("操作来源不合法，允许值：PC_WEB、APP、H5、SYSTEM");
            }
        }*/

        // 5. 执行修改（仅更新允许修改的字段，保护核心信息）
        if (updateDTO.getRemark() != null) {
            log.setRemark(updateDTO.getRemark());
        }
        if (updateDTO.getIsSyncH5Design() != null) {
            log.setIsSyncH5Design(updateDTO.getIsSyncH5Design());
        }
        if (updateDTO.getOperateSource() != null) {
            log.setOperateSource(updateDTO.getOperateSource());
        }

        // 初始状态代办才可修改动作
        if (StringUtils.isNotBlank(log.getOperateAction()) && OperateActionEnum.ADD_DESIGN_TODO.getCode().equals(log.getOperateAction())){
            log.setOperateAction(updateDTO.getOperateAction());
        }

        // 6. 保存修改
        boolean updateSuccess = updateById(log);
        if (updateSuccess) {
            return AjaxResult.success("日志修改成功", log.getId());
        } else {
            return AjaxResult.error("日志修改失败，可能未发生变更");
        }
    }

    @Override
    public void saveMaterialLog(
            Long businessId,
            String businessName,
            Long operatorId,
            String operatorName,
            String operateAction,
            String beforeStatus,
            String afterStatus,
            String remark
    ) {
        OperationLog log = new OperationLog();
        log.setOperateUserId(operatorId);
        log.setOperateUserName(operatorName);
        log.setBusinessType("MATERIAL"); // 物料管理模块标识
        log.setBusinessId(businessId.toString()); // 转换为字符串存储
        log.setBusinessName(businessName);
        log.setOperateAction(operateAction);
        log.setBeforeStatus(beforeStatus);
        log.setAfterStatus(afterStatus);
        log.setRemark(remark);
        log.setOperateSource("PC_WEB"); // 默认PC端
        log.setIsDeleted(0); // 未删除
        save(log);
    }
}
